﻿using System;
using System.Collections.Generic;
using Talented.Core.Exceptions;

namespace Talented.Core.Model.Talents
{
	public class Talent : ITalent
	{
		#region constants
		public const string LevelValidationError = "Level does not meet expectation (from 1 to 5)";
		#endregion

		#region fields
		private byte _level = 1;

		private static readonly Dictionary<TalentQualityEnum, double> QualityMigth = new Dictionary<TalentQualityEnum, double>
		{
			{TalentQualityEnum.Blue, 36},
			{TalentQualityEnum.Green, 30},
			{TalentQualityEnum.Orange, 44.4},
			{TalentQualityEnum.Violet, 43.2},
			{TalentQualityEnum.Yellow, 24}
		};

		protected readonly Dictionary<CharacteristicEnum, double> Characteristics;
		protected readonly Dictionary<CharacteristicEnum, double> CharacteristicsGroth;

		private readonly ITalentConfiguration _conficuration;
		#endregion

		#region properties
		public byte Level
		{
			get { return _level; }
			set
			{
				if (value > 5)
					throw new ArgumentOutOfRangeException("value");

				_level = value;
			}
		}

		public TalentQualityEnum Quality { get; private set; }

		public Guid TalentIdentifier { get; protected set; }
		#endregion

		public Talent(ITalentConfiguration configuration)
		{
			if (configuration == null)
				throw new ArgumentNullException("configuration");

			if (!configuration.Validate())
				throw new ConfigurationException();

			Characteristics = configuration.Characteristics ?? new Dictionary<CharacteristicEnum, double>();
			CharacteristicsGroth = configuration.CharacteristicsGroth ?? new Dictionary<CharacteristicEnum, double>();
			Quality = configuration.Quality;
			TalentIdentifier = configuration.TalentIdentifier;

			_conficuration = configuration;
		}

		#region public methods
		public virtual double GetMight()
		{
			var startingMigth = QualityMigth[Quality];
			var migth = startingMigth + 0.075*startingMigth*(Level - 1);
			return Math.Round(migth, 0, MidpointRounding.ToEven);
		}

		public virtual double GetValue(CharacteristicEnum сharacteristicType)
		{
			double initialValue;
			double stepValue;
			if (!Characteristics.TryGetValue(сharacteristicType, out initialValue) || !CharacteristicsGroth.TryGetValue(сharacteristicType, out stepValue))
				throw new TalentConfigurationException(string.Format("Talent doesn`t contain {0}", сharacteristicType));

			return Math.Round(initialValue + stepValue*Level, 1);
		}

		public virtual void MaximizeParameter()
		{
			// Nothing to do here
		}

		public virtual void MinimizeParameter()
		{
			// Nothing to do here
		}

		public virtual bool Validate()
		{
			return 
				Level >= 1 
				&& Level <= 5
				&& _conficuration != null
				&& _conficuration.Validate();
		}

		public virtual bool Validate(out List<string> validationList)
		{
			_conficuration.Validate(out validationList);

			if (Level < 1 || Level > 5)
				validationList.Add(LevelValidationError);

			return validationList.Count == 0;
		}
		#endregion
	}
}
